//
//  APIConfig.swift
//  Example
//
//  Created by remy on 2019/4/8.
//  Copyright © 2019 com.Risac. All rights reserved.
//

import struct Alamofire.HTTPMethod

typealias UploadResource = (data: Data, fileName: String?, mineType: String?)

enum API {
    /// 自由请求
    case FREE(String, HTTPMethod, [String: Any]?, [String: Any]?)
    /// 无参数GET请求
    case PLAIN_GET(String)
    /// 有参数GET请求
    case NORMAL_GET(String, [String: Any]?)
    /// 无参数POST请求
    case PLAIN_POST(String)
    /// 有参数POST请求
    case NORMAL_POST(String, [String: Any]?)
    /// 上传POST请求
    case UPLOAD_POST(String, [String: Any]?, [String: UploadResource]?)
    /// 无参数PUT请求
    case PLAIN_PUT(String)
    /// 有参数PUT请求
    case NORMAL_PUT(String, [String: Any]?)
    /// 上传PUT请求
    case UPLOAD_PUT(String, [String: Any]?, [String: UploadResource]?)
    /// 无参数DELETE请求
    case PLAIN_DELETE(String)
    /// 有参数DELETE请求
    case NORMAL_DELETE(String, [String: Any]?)
    indirect case CHANNEL(Server, API)
    enum Server {
        case `default`
        var urlStr: String {
            switch self {
            default:
                if env == .development {
                    return "http://api.staging.xuanxiaodi.com"
                }
                return "https://api.xuanxiaodi.com"
            }
        }
        var url: URL {
            return self.urlStr.url!
        }
    }
    enum Environment {
        case custom // 自定义环境
        case development // 开发环境
        case test // 测试环境
        case preview // 预发环境
        case production // 生产环境
    }
    static var env: Environment = .production
}

extension API: TargetType {
    var baseURL: URL {
        if case let .CHANNEL(server, _) = self {
            return server.url
        }
        return Server.default.url
    }
    
    var path: String {
        var operate: API = self
        if case let .CHANNEL(_, api) = self {
            operate = api
        }
        switch operate {
        case let .FREE(path, _, _, _), let .PLAIN_GET(path), let .NORMAL_GET(path, _), let .PLAIN_POST(path), let .NORMAL_POST(path, _), let .UPLOAD_POST(path, _, _), let .PLAIN_PUT(path), let .NORMAL_PUT(path, _), let .UPLOAD_PUT(path, _, _), let .PLAIN_DELETE(path), let .NORMAL_DELETE(path, _):
            return "\(path)"
        default:
            return ""
        }
    }
    
    var method: Moya.Method {
        switch self {
        case .PLAIN_POST, .NORMAL_POST, .UPLOAD_POST:
            return .post
        case .PLAIN_PUT, .NORMAL_PUT, .UPLOAD_PUT:
            return .put
        case .PLAIN_DELETE, .NORMAL_DELETE:
            return .delete
        case let .FREE(_, method, _, _):
            return method
        default:
            return .get
        }
    }
    
    var sampleData: Data {
        return Data()
    }
    
    var task: Task {
        var operate: API = self
        if case let .CHANNEL(_, api) = self {
            operate = api
        }
        switch operate {
        case let .FREE(_, _, bodyParams, urlParams):
            return .requestCompositeParameters(bodyParameters: bodyParams ?? [:], bodyEncoding: JSONEncoding.default, urlParameters: urlParams ?? [:])
        case .PLAIN_GET, .PLAIN_POST, .PLAIN_PUT, .PLAIN_DELETE:
            return .requestPlain
        case let .NORMAL_GET(_, params):
            if let params = params {
                return .requestParameters(parameters: params, encoding: URLEncoding.default)
            } else {
                return .requestPlain
            }
        case let .NORMAL_POST(_, params), let .NORMAL_PUT(_, params), let .NORMAL_DELETE(_, params):
            if let params = params {
                return .requestParameters(parameters: params, encoding: JSONEncoding.default)
            } else {
                return .requestPlain
            }
        case let .UPLOAD_POST(_, params, files), let .UPLOAD_PUT(_, params, files):
            if let files = files {
                var fileParams: [Moya.MultipartFormData] = []
                files.forEach {
                    let provider = Moya.MultipartFormData.FormDataProvider.data($1.data)
                    fileParams.append(Moya.MultipartFormData(provider: provider, name: $0, fileName: $1.fileName, mimeType: $1.mineType))
                }
                return .uploadCompositeMultipart(fileParams, urlParameters: params ?? [:])
            } else {
                if let params = params {
                    return .requestParameters(parameters: params, encoding: JSONEncoding.default)
                } else {
                    return .requestPlain
                }
            }
        default:
            return .requestPlain
        }
    }
    
    var validationType: ValidationType {
        return .successAndRedirectCodes
    }
    
    var headers: [String: String]? {
        return [:]
    }
}
